<?php
/**  
 * @file token.php  
 * @author 辰然 <3469807212@qq.com>  
 * @created 2024年12月1日  
 * @signature "创意无限"  
 * @copyright Copyright (c) 2024 辰然. All rights reserved. 本软件版权归辰然所有，未经许可，不得开源或用于商业用途。  
 * 注意: 根据版权声明，此代码允许开源。  
 */  
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: Content-Type, Authorization');

// 错误日志配置
ini_set('display_errors', 0);
ini_set('log_errors', 1);
error_reporting(E_ALL);
ini_set('error_log', __DIR__ . '/../logs/wx_error.log');


define('APPID', '#'); 
define('APPSECRET', '#');
define('WX_TOKEN', '#');
define('TOKEN_FILE', __DIR__ . '/../data/tokens.json');
define('USER_FILE', __DIR__ . '/../data/users.json');

// 处理请求
$action = $_GET['action'] ?? '';

// 验证签名
if(isset($_GET['signature']) && isset($_GET['timestamp']) && isset($_GET['nonce'])) {
    $signature = $_GET['signature'];
    $timestamp = $_GET['timestamp'];
    $nonce = $_GET['nonce'];
    $token = WX_TOKEN;
    
    $tmpArr = array($token, $timestamp, $nonce);
    sort($tmpArr, SORT_STRING);
    $tmpStr = implode($tmpArr);
    $tmpStr = sha1($tmpStr);
    
    if($tmpStr == $signature) {
        // 首次验证时返回 echostr
        if(isset($_GET['echostr'])) {
            die($_GET['echostr']);
        }
    } else {
        die('签名验证失败');
    }
}

try {
    switch($action) {
        case 'qrcode':
            header('Content-Type: application/json');
            echo json_encode(generateQrCode());
            break;
            
        case 'login':
            header('Content-Type: text/html; charset=utf-8');
            handleLogin();
            break;
            
        case 'check':
            header('Content-Type: application/json');
            echo json_encode(checkLoginStatus());
            break;
            
        case 'bind':
            header('Content-Type: application/json');
            echo json_encode(handleWxCallback());
            break;
            
        default:
            throw new Exception('未知的操作类型');
    }
} catch(Exception $e) {
    header('Content-Type: application/json');
    echo json_encode([
        'success' => false,
        'error' => $e->getMessage()
    ]);
}

function generateQrCode() {
    try {
        // 生成唯一标识
        $scene = md5(uniqid());
        
        // 生成登录URL
        $loginUrl = "https://chat.orderease.cn/api/wxauth.php?action=login&scene=" . urlencode($scene);
        
        // 使用第三方服务生成二维码
        $qrUrl = "https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=" . urlencode($loginUrl);
        
        // 保存场景值
        $tokenFile = TOKEN_FILE;
        if (!file_exists(dirname($tokenFile))) {
            mkdir(dirname($tokenFile), 0777, true);
        }
        
        $tokens = loadJsonFile($tokenFile);
        $tokens[$scene] = [
            'create_time' => time(),
            'expire_time' => time() + 1800,
            'status' => 'pending'
        ];
        saveJsonFile($tokenFile, $tokens);
        
        return [
            'success' => true,
            'data' => [
                'qr_url' => $qrUrl,
                'ticket' => $scene,
                'expire_seconds' => 1800
            ]
        ];
    } catch(Exception $e) {
        error_log("生成二维码错误: " . $e->getMessage());
        return [
            'success' => false,
            'error' => $e->getMessage()
        ];
    }
}

function handleLogin() {
    $scene = $_GET['scene'] ?? '';
    if (!$scene) {
        die('参数错误');
    }
    
    // 获取场景值信息
    $tokens = loadJsonFile(TOKEN_FILE);
    if (!isset($tokens[$scene]) || $tokens[$scene]['expire_time'] < time()) {
        die('二维码已过期');
    }
    
    // 获取公众号二维码URL
    try {
        $accessToken = getAccessToken();
        $url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token={$accessToken}";
        $data = [
            'expire_seconds' => 1800,
            'action_name' => 'QR_STR_SCENE',
            'action_info' => [
                'scene' => [
                    'scene_str' => $scene
                ]
            ]
        ];
        
        $result = httpPost($url, json_encode($data));
        $response = json_decode($result, true);
        
        if (!isset($response['ticket'])) {
            throw new Exception('获取二维码ticket失败');
        }
        
        $qrcodeUrl = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" . urlencode($response['ticket']);
        
        // 保存二维码URL到tokens中
        $tokens[$scene]['qrcode_url'] = $qrcodeUrl;
        saveJsonFile(TOKEN_FILE, $tokens);
        
    } catch(Exception $e) {
        error_log("生成登录二维码错误: " . $e->getMessage());
        // 如果获取失败，使用备用的二维码生成服务
        $qrcodeUrl = "https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=" . urlencode("https://chat.orderease.cn/api/wxauth.php?action=login&scene=" . $scene);
    }
    
    // 输出登录页面
    echo '<!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>扫码登录</title>
        <style>
            body {
                margin: 0;
                padding: 20px;
                font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
                display: flex;
                flex-direction: column;
                align-items: center;
                justify-content: center;
                min-height: 100vh;
                background: #f5f5f5;
            }
            .container {
                max-width: 500px;
                width: 100%;
                background: white;
                padding: 30px;
                border-radius: 12px;
                box-shadow: 0 2px 10px rgba(0,0,0,0.1);
                text-align: center;
            }
            h1 {
                margin: 0 0 20px;
                color: #333;
                font-size: 24px;
            }
            .qrcode {
                width: 200px;
                height: 200px;
                margin: 20px auto;
                background: #f8f8f8;
                padding: 10px;
                border-radius: 8px;
            }
            .qrcode img {
                width: 100%;
                height: 100%;
                object-fit: contain;
            }
            .tips {
                color: #666;
                line-height: 1.6;
                margin: 20px 0;
            }
            .button {
                display: inline-block;
                padding: 10px 20px;
                background: #07C160;
                color: white;
                text-decoration: none;
                border-radius: 5px;
                margin-top: 20px;
            }
            .refresh-btn {
                display: none;
                padding: 8px 16px;
                background: #07C160;
                color: white;
                border: none;
                border-radius: 4px;
                cursor: pointer;
                margin-top: 10px;
            }
            .error-tips {
                color: #ff4d4f;
                margin: 10px 0;
                display: none;
            }
        </style>
    </head>
    <body>
        <div class="container">
            <h1>扫码登录</h1>
            <div class="tips">
                <p>请使用微信扫描下方二维码关注公众号并登录</p>
            </div>
            <div class="qrcode">
                <img src="' . htmlspecialchars($qrcodeUrl) . '" alt="公众号二维码">
            </div>
            <p class="tips">扫码后将自动完成登录</p>
            <p class="error-tips">二维码加载失败，请点击刷新</p>
            <button class="refresh-btn" onclick="refreshQrCode()">刷新二维码</button>
        </div>
        <script>
            let checkCount = 0;
            const maxChecks = 90; // 最多检查3分钟
            
            // 检查图片加载状态
            document.querySelector(".qrcode img").onerror = function() {
                this.style.display = "none";
                document.querySelector(".error-tips").style.display = "block";
                document.querySelector(".refresh-btn").style.display = "inline-block";
            };
            
            // 刷新二维码
            function refreshQrCode() {
                window.location.reload();
            }
            
            // 检查登录状态
            function checkLoginStatus() {
                if (checkCount >= maxChecks) {
                    document.querySelector(".error-tips").textContent = "二维码已过期，请刷新页面重试";
                    document.querySelector(".error-tips").style.display = "block";
                    document.querySelector(".refresh-btn").style.display = "inline-block";
                    return;
                }
                
                fetch("https://chat.orderease.cn/api/wxauth.php?action=check", {
                    method: "POST",
                    headers: {
                        "Content-Type": "application/json"
                    },
                    body: JSON.stringify({
                        ticket: "' . htmlspecialchars($scene) . '"
                    })
                })
                .then(response => response.json())
                .then(data => {
                    console.log("检查登录状态:", data); // 调试输出
                    
                    if(data.success && data.data.is_login) {
                        // 更新提示文本
                        document.querySelector(".tips").textContent = "登录成功，正在跳转...";
                        
                        // 通知父窗口登录成功
                        if(window.opener) {
                            window.opener.postMessage({
                                type: "wxLoginSuccess",
                                scene: "' . htmlspecialchars($scene) . '",
                                token: data.data.token,
                                user_info: data.data.user_info
                            }, "*");
                            
                            // 延迟关闭窗口
                            setTimeout(() => window.close(), 1000);
                        }
                    } else {
                        checkCount++;
                        // 继续检查
                        setTimeout(checkLoginStatus, 2000);
                    }
                })
                .catch(error => {
                    console.error("检查登录状态失败:", error);
                    checkCount++;
                    // 发生错误时也继续检查
                    setTimeout(checkLoginStatus, 2000);
                });
            }
            
            // 开始检查登录状态
            checkLoginStatus();
        </script>
    </body>
    </html>';
}

function loadJsonFile($file) {
    if(!file_exists($file)) {
        return [];
    }
    $content = file_get_contents($file);
    return $content ? json_decode($content, true) : [];
}

function saveJsonFile($file, $data) {
    file_put_contents($file, json_encode($data, JSON_PRETTY_PRINT));
}

// 检查登录状态
function checkLoginStatus() {
    try {
        $ticket = '';
        $postData = json_decode(file_get_contents('php://input'), true);
        if ($postData && isset($postData['ticket'])) {
            $ticket = $postData['ticket'];
        }
        
        // 如果有ticket，检查扫码状态
        if($ticket) {
            $tokens = loadJsonFile(TOKEN_FILE);
            error_log("检查登录状态 - ticket: $ticket, tokens: " . json_encode($tokens)); // 调试日志
            
            if(isset($tokens[$ticket])) {
                if($tokens[$ticket]['status'] === 'success' && isset($tokens[$ticket]['openid'])) {
                    $openid = $tokens[$ticket]['openid'];
                    $users = loadJsonFile(USER_FILE);
                    
                    if(isset($users[$openid])) {
                        // 生成新token
                        $newToken = md5(uniqid() . $openid);
                        $users[$openid]['token'] = $newToken;
                        $users[$openid]['token_expire'] = time() + 86400;
                        $users[$openid]['last_login'] = time();
                        saveJsonFile(USER_FILE, $users);
                        
                        error_log("用户登录成功 - openid: $openid"); // 调试日志
                        
                        return [
                            'success' => true,
                            'data' => [
                                'is_login' => true,
                                'token' => $newToken,
                                'user_info' => [
                                    'openid' => $openid,
                                    'nickname' => $users[$openid]['nickname'],
                                    'avatar' => $users[$openid]['avatar']
                                ]
                            ]
                        ];
                    }
                }
                
                // 如果二维码已过期
                if ($tokens[$ticket]['expire_time'] < time()) {
                    return [
                        'success' => true,
                        'data' => [
                            'is_login' => false,
                            'expired' => true
                        ]
                    ];
                }
            }
        }
        
        return [
            'success' => true,
            'data' => [
                'is_login' => false
            ]
        ];
    } catch(Exception $e) {
        error_log("检查登录状态错误: " . $e->getMessage());
        return [
            'success' => false,
            'error' => $e->getMessage()
        ];
    }
}

// 处理微信回调
function handleWxCallback() {
    try {
        $xmlData = file_get_contents('php://input');
        error_log("收到微信回调: " . $xmlData); // 调试日志
        
        if (!$xmlData) {
            throw new Exception('未接收到数据');
        }
        
        // 解析XML
        $msg = simplexml_load_string($xmlData, 'SimpleXMLElement', LIBXML_NOCDATA);
        if (!$msg) {
            throw new Exception('解析XML失败');
        }
        
        // 记录接收到的消息
        error_log("收到微信消息: " . $xmlData);
        
        // 处理关注事件
        if ($msg->MsgType == 'event') {
            $openid = (string)$msg->FromUserName;
            
            // 获取用户信息
            $accessToken = getAccessToken();
            $userInfo = getUserInfo($accessToken, $openid);
            
            // 更新用户数据
            $users = loadJsonFile(USER_FILE);
            $users[$openid] = [
                'openid' => $openid,
                'nickname' => $userInfo['nickname'] ?? '',
                'avatar' => $userInfo['headimgurl'] ?? '',
                'create_time' => time(),
                'last_login' => time(),
                'token' => md5(uniqid() . $openid),
                'token_expire' => time() + 86400
            ];
            saveJsonFile(USER_FILE, $users);
            
            // 处理扫码事件
            if ($msg->Event == 'SCAN' || ($msg->Event == 'subscribe' && isset($msg->EventKey))) {
                $scene = str_replace('qrscene_', '', (string)$msg->EventKey);
                error_log("处理扫码事件 - scene: $scene, event: {$msg->Event}"); // 调试日志
                
                $tokens = loadJsonFile(TOKEN_FILE);
                if (isset($tokens[$scene])) {
                    $tokens[$scene]['status'] = 'success';
                    $tokens[$scene]['openid'] = $openid;
                    saveJsonFile(TOKEN_FILE, $tokens);
                    error_log("更新扫码状态成功 - scene: $scene, openid: $openid"); // 调试日志
                }
            }
            
            // 返回成功响应
            return [
                'success' => true,
                'data' => [
                    'openid' => $openid
                ]
            ];
        }
        
        return [
            'success' => true
        ];
        
    } catch(Exception $e) {
        error_log("处理微信回调错误: " . $e->getMessage());
        return [
            'success' => false,
            'error' => $e->getMessage()
        ];
    }
}

// 获取用户信息
function getUserInfo($accessToken, $openid) {
    $url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token={$accessToken}&openid={$openid}&lang=zh_CN";
    $result = httpGet($url);
    $data = json_decode($result, true);
    
    if (!isset($data['errcode'])) {
        return $data;
    }
    
    error_log("获取用户信息失败: " . json_encode($data));
    throw new Exception('获取用户信息失败: ' . ($data['errmsg'] ?? '未知错误'));
}

// 获取access_token
function getAccessToken() {
    try {
        $cacheFile = __DIR__ . '/../data/access_token.json';
        
        // 确保目录存在
        if (!file_exists(dirname($cacheFile))) {
            mkdir(dirname($cacheFile), 0777, true);
        }
        
        $data = loadJsonFile($cacheFile);
        
        if(!$data || !isset($data['expire_time']) || $data['expire_time'] < time()) {
            $url = sprintf(
                "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",
                APPID,
                APPSECRET
            );
            
            $result = httpGet($url);
            $response = json_decode($result, true);
            
            if(isset($response['access_token'])) {
                $data = [
                    'access_token' => $response['access_token'],
                    'expire_time' => time() + 7000
                ];
                saveJsonFile($cacheFile, $data);
                return $data['access_token'];
            }
            
            throw new Exception('获取access_token失败: ' . json_encode($response));
        }
        
        return $data['access_token'];
    } catch(Exception $e) {
        error_log("获取access_token错误: " . $e->getMessage());
        throw $e;
    }
}

// HTTP GET请求
function httpGet($url) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($ch, CURLOPT_TIMEOUT, 10);
    
    $result = curl_exec($ch);
    
    if($result === false) {
        $error = curl_error($ch);
        curl_close($ch);
        throw new Exception('CURL请求失败: ' . $error);
    }
    
    curl_close($ch);
    return $result;
}

// HTTP POST请求
function httpPost($url, $data) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    curl_setopt($ch, CURLOPT_TIMEOUT, 10);
    
    $result = curl_exec($ch);
    
    if($result === false) {
        $error = curl_error($ch);
        curl_close($ch);
        throw new Exception('CURL请求失败: ' . $error);
    }
    
    curl_close($ch);
    return $result;
} 